package com.ndood.admin.controller.user;

import java.net.URLEncoder;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.context.request.ServletWebRequest;

import com.ndood.admin.core.constaints.AdminErrCode;
import com.ndood.admin.core.exception.AdminException;
import com.ndood.admin.core.properties.AdminProperties;
import com.ndood.admin.core.util.AesEncryptUtil;
import com.ndood.admin.core.util.RegexUtils;
import com.ndood.admin.core.web.tools.EmailUtils;
import com.ndood.admin.core.web.tools.SessionUtils;
import com.ndood.admin.pojo.comm.vo.AdminResultVo;
import com.ndood.admin.pojo.system.dto.UserDto;
import com.ndood.admin.service.user.AccountBindingService;
import com.ndood.admin.service.user.AccountInfoService;
import com.ndood.core.validate.code.ValidateCodeException;
import com.ndood.core.validate.code.ValidateCodeProcessorHolder;
import com.ndood.core.validate.code.ValidateCodeType;

import cn.hutool.core.codec.Base64;
import lombok.extern.slf4j.Slf4j;

/**
 * 账户绑定管理
 */
@Controller
@Slf4j
public class AccountBindingController {

	@Autowired
	private AdminProperties adminProperties;
	
	@Autowired
	private EmailUtils emailUtils;
	
	@Autowired
	private AccountBindingService accountBindingService;
	
	@Autowired
	private AccountInfoService accountInfoService;
	
	@Autowired
	private SessionUtils sessionUtils;
	
	/**
	 * 系统中的校验码处理器
	 */
	@Autowired
	private ValidateCodeProcessorHolder validateCodeProcessorHolder;
	
	/**
	 * 跳转到账户绑定页
	 */
	@GetMapping("/user/account/binding")
	public String toSocial(){
		return "user/account/binding/account_binding";
	}
	
	/**
	 * 新绑定
	 */
	@PostMapping("/user/account/binding/to_new_binding")
	public String toNewBinding(String type, Model model) throws Exception{
		if(StringUtils.isBlank(type)) {
			throw new AdminException(AdminErrCode.ERR_PARAM,"type不能为空！");
		}
		if(!type.equals("email")&&!type.equals("mobile")) {
			throw new AdminException(AdminErrCode.ERR_PARAM,"无效的type！");
		}
		
		model.addAttribute("type", type);
		return "user/account/binding/new_binding";
	}
	
	/**
	 * 重新绑定
	 */
	@PostMapping("/user/account/binding/new_binding_mobile")
	@ResponseBody
	public AdminResultVo newBindingMobile(String mobile, String imageCode, String smsCode, HttpServletRequest request, HttpServletResponse response) throws Exception{
		log.debug("Step1: 校验请求参数");
		if(StringUtils.isBlank(mobile)||!RegexUtils.checkMobile(mobile)) {
			throw new AdminException(AdminErrCode.ERR_PARAM,"无效的手机号！");
		}
		if(StringUtils.isBlank(imageCode)) {
			throw new AdminException(AdminErrCode.ERR_PARAM,"图片验证码为空！");
		}
		if(StringUtils.isBlank(smsCode)) {
			throw new AdminException(AdminErrCode.ERR_PARAM,"短信验证码为空！");
		}
		
		log.debug("Step2: 验证码校验");
		// 判断图片验证码
		try {
			validateCodeProcessorHolder.findValidateCodeProcessor(ValidateCodeType.IMAGE)
					.validate(new ServletWebRequest(request, response));
		} catch (ValidateCodeException exception) {
			throw new AdminException(AdminErrCode.ERR_PARAM,"图片验证码不正确！");
		}
		// 判断短信验证码
		try {
			validateCodeProcessorHolder.findValidateCodeProcessor(ValidateCodeType.SMS)
					.validate(new ServletWebRequest(request, response));
		} catch (ValidateCodeException exception) {
			throw new AdminException(AdminErrCode.ERR_PARAM,"短信验证码不正确！");
		}
		
		log.debug("Step3: 检查该手机号是否已绑定其它账号");
		boolean isBind = accountBindingService.isMobileBindingAccounts(mobile);
		if(isBind) {
			throw new AdminException(AdminErrCode.ERR_OTHER,"绑定失败，该手机已经绑定其它账号！");
		}
		
		log.debug("Step4: 绑定手机");
		UserDetails userInfo = sessionUtils.getLoginUserInfo();
		if(userInfo==null) {
			throw new AdminException(AdminErrCode.ERR_OTHER,"用户不存在！");
		}
		String userId = userInfo.getUsername();
		accountBindingService.bindingMobile(userId, mobile);
		
		return AdminResultVo.ok().setMsg("手机号绑定成功！");
	}
	
	/**
	 * 新绑定邮箱
	 */
	@PostMapping("/user/account/binding/new_binding_email")
	@ResponseBody
	public AdminResultVo newBindingEmail(String email, String imageCode, HttpServletRequest request, HttpServletResponse response) throws Exception{
		log.debug("Step1: 校验请求参数");
		if(StringUtils.isBlank(email)||!RegexUtils.checkEmail(email)) {
			throw new AdminException(AdminErrCode.ERR_PARAM,"无效的邮箱！");
		}
		if(StringUtils.isBlank(imageCode)) {
			throw new AdminException(AdminErrCode.ERR_PARAM,"图片验证码为空！");
		}
		
		log.debug("Step2: 验证码校验");
		// 判断图片验证码
		try {
			validateCodeProcessorHolder.findValidateCodeProcessor(ValidateCodeType.IMAGE)
					.validate(new ServletWebRequest(request, response));
		} catch (ValidateCodeException exception) {
			throw new AdminException(AdminErrCode.ERR_PARAM,"图片验证码不正确！");
		}
		
		log.debug("Step3: 检查该邮箱是否已绑定其它账号");
		boolean isBind = accountBindingService.isEmailBindingAccounts(email);
		if(isBind) {
			throw new AdminException(AdminErrCode.ERR_OTHER,"绑定失败，该邮箱已经绑定其它账号！");
		}
		
		log.debug("Step4: 更新邮箱，并发送激活邮件");
		UserDetails userInfo = sessionUtils.getLoginUserInfo();
		if(userInfo==null) {
			throw new AdminException(AdminErrCode.ERR_OTHER,"用户不存在！");
		}
		String userId = userInfo.getUsername();
		accountBindingService.bindingEmail(userId, email);
		
		String aesKey = adminProperties.getEmail().getEncryptKey();
		String from = adminProperties.getEmail().getFrom();
		String domain = adminProperties.getDomain();
		String activateUrl = adminProperties.getEmail().getActivationUrl();
		String active = AesEncryptUtil.encrypt(userId + "_" + domain + "_" + from, aesKey);
		String linkid = URLEncoder.encode(Base64.encode(userId, "UTF-8"), "UTF-8");
		emailUtils.sendActivationEmail(email, from, "payboyPlus激活邮件", email, domain, activateUrl, active,
				linkid);
		return AdminResultVo.ok().setMsg("邮箱绑定成功！");
	}
	
	/**
	 * 重新发送激活邮件
	 */
	@PostMapping("/user/account/binding/resend_active_email")
	@ResponseBody
	public AdminResultVo resendActiveEmail(String email) throws Exception {
		
		log.debug("Step1: 校验请求参数");
		if(StringUtils.isBlank(email)) {
			throw new AdminException(AdminErrCode.ERR_PARAM,"邮箱不能为空！");
		}
		
		log.debug("Step2: 获取用户信息");
		UserDetails userInfo = sessionUtils.getLoginUserInfo();
		if(userInfo==null) {
			throw new AdminException(AdminErrCode.ERR_OTHER,"用户不存在！");
		}
		
		log.debug("Step3: 发送激活邮件");
		String userId = userInfo.getUsername();
		String aesKey = adminProperties.getEmail().getEncryptKey();
		String from = adminProperties.getEmail().getFrom();
		String domain = adminProperties.getDomain();
		String activateUrl = adminProperties.getEmail().getActivationUrl();
		String active = AesEncryptUtil.encrypt(userId + "_" + domain + "_" + from, aesKey);
		String linkid = URLEncoder.encode(Base64.encode(userId, "UTF-8"), "UTF-8");
		emailUtils.sendActivationEmail(email, from, "payboyPlus激活邮件", email, domain, activateUrl, active,
				linkid);
		return AdminResultVo.ok().setMsg("激活邮件发送成功！");

	}
	
	/**
	 * 更换绑定
	 */
	@PostMapping("/user/account/binding/to_change_binding")
	public String toChangeBinding(String type, Model model) throws AdminException{
		if(StringUtils.isBlank(type)) {
			throw new AdminException(AdminErrCode.ERR_PARAM,"type不能为空！");
		}
		if(!type.equals("email")&&!type.equals("mobile")) {
			throw new AdminException(AdminErrCode.ERR_PARAM,"无效的type！");
		}
		
		model.addAttribute("type", type);
		return "user/account/binding/change_binding";
	}
	
	/**
	 * 重新绑定
	 */
	@PostMapping("/user/account/binding/change_binding_mobile")
	@ResponseBody
	public AdminResultVo changeBindingMobile(String mobile, String imageCode, String smsCode, HttpServletRequest request, HttpServletResponse response) throws Exception{
		log.debug("Step1: 校验请求参数");
		if(StringUtils.isBlank(mobile)||!RegexUtils.checkMobile(mobile)) {
			throw new AdminException(AdminErrCode.ERR_PARAM,"无效的手机号！");
		}
		if(StringUtils.isBlank(imageCode)) {
			throw new AdminException(AdminErrCode.ERR_PARAM,"图片验证码为空！");
		}
		if(StringUtils.isBlank(smsCode)) {
			throw new AdminException(AdminErrCode.ERR_PARAM,"短信验证码为空！");
		}
		
		log.debug("Step2: 验证码校验");
		// 判断图片验证码
		try {
			validateCodeProcessorHolder.findValidateCodeProcessor(ValidateCodeType.IMAGE)
					.validate(new ServletWebRequest(request, response));
		} catch (ValidateCodeException exception) {
			throw new AdminException(AdminErrCode.ERR_PARAM,"图片验证码不正确！");
		}
		// 判断短信验证码
		try {
			validateCodeProcessorHolder.findValidateCodeProcessor(ValidateCodeType.SMS)
					.validate(new ServletWebRequest(request, response));
		} catch (ValidateCodeException exception) {
			throw new AdminException(AdminErrCode.ERR_PARAM,"短信验证码不正确！");
		}
		
		log.debug("Step3: 检查该手机号是否已绑定其它账号");
		boolean isBind = accountBindingService.isMobileBindingAccounts(mobile);
		if(isBind) {
			throw new AdminException(AdminErrCode.ERR_OTHER,"绑定失败，该手机已经绑定其它账号！");
		}

		log.debug("Step4: 绑定手机");
		UserDetails userInfo = sessionUtils.getLoginUserInfo();
		if(userInfo==null) {
			throw new AdminException(AdminErrCode.ERR_OTHER,"用户不存在！");
		}
		String userId = userInfo.getUsername();
		accountBindingService.bindingMobile(userId, mobile);
		
		return AdminResultVo.ok().setMsg("手机更换绑定成功！");
	}
	
	/**
	 * 新绑定邮箱
	 */
	@PostMapping("/user/account/binding/change_binding_email")
	@ResponseBody
	public AdminResultVo changeBindingEmail(String email, String imageCode, HttpServletRequest request, HttpServletResponse response) throws Exception{
		log.debug("Step1: 校验请求参数");
		if(StringUtils.isBlank(email)||!RegexUtils.checkEmail(email)) {
			throw new AdminException(AdminErrCode.ERR_PARAM,"无效的邮箱！");
		}
		if(StringUtils.isBlank(imageCode)) {
			throw new AdminException(AdminErrCode.ERR_PARAM,"图片验证码为空！");
		}
		
		log.debug("Step2: 验证码校验");
		// 判断图片验证码
		try {
			validateCodeProcessorHolder.findValidateCodeProcessor(ValidateCodeType.IMAGE)
					.validate(new ServletWebRequest(request, response));
		} catch (ValidateCodeException exception) {
			throw new AdminException(AdminErrCode.ERR_PARAM,"图片验证码不正确！");
		}
		
		log.debug("Step3: 检查该邮箱是否已绑定其它账号");
		boolean isBind = accountBindingService.isEmailBindingAccounts(email);
		if(isBind) {
			throw new AdminException(AdminErrCode.ERR_OTHER,"绑定失败，该邮箱已经绑定其它账号！");
		}
		
		log.debug("Step4: 更新邮箱，并发送激活邮件");
		UserDetails userInfo = sessionUtils.getLoginUserInfo();
		if(userInfo==null) {
			throw new AdminException(AdminErrCode.ERR_OTHER,"用户不存在！");
		}
		String userId = userInfo.getUsername();
		accountBindingService.bindingEmail(userId, email);
		
		String aesKey = adminProperties.getEmail().getEncryptKey();
		String from = adminProperties.getEmail().getFrom();
		String domain = adminProperties.getDomain();
		String activateUrl = adminProperties.getEmail().getActivationUrl();
		String active = AesEncryptUtil.encrypt(userId + "_" + domain + "_" + from, aesKey);
		String linkid = URLEncoder.encode(Base64.encode(userId, "UTF-8"), "UTF-8");
		emailUtils.sendActivationEmail(email, from, "payboyPlus更换绑定邮件", email, domain, activateUrl, active,
				linkid);
		return AdminResultVo.ok().setMsg("邮箱更换绑定成功！");
	}
	
	/**
	 * 查询用户信息，返回加码数据
	 */
	@PostMapping("/user/account/binding/get")
	@ResponseBody
	public AdminResultVo getAccountInfo() throws Exception{
		UserDetails userDetails = (UserDetails) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
		String userId = userDetails.getUsername();
		UserDto accountInfo = accountInfoService.getAccountSimpleInfoById(userId);
		// 绑定页面显示的是带星号的手机和邮箱
		accountInfo.setMobile(accountInfo.getEncryptMobile());
		// accountInfo.setEmail(accountInfo.getEncryptEmail());
		return AdminResultVo.ok().setData(accountInfo).setMsg("获取账户信息成功！");
	}
	
	/**
	 * 校验原手机号是否正确
	 */
	@GetMapping("/user/account/binding/check_old_mobile")
	@ResponseBody
	public AdminResultVo checkOldMobile(String mobile) throws Exception{
		if(StringUtils.isBlank(mobile)) {
			throw new AdminException(AdminErrCode.ERR_PARAM,"手机号不合法！");
		}
		UserDetails userInfo = sessionUtils.getLoginUserInfo();
		String userId = userInfo.getUsername();
		UserDto accountInfo = accountInfoService.getAccountSimpleInfoById(userId);
		
		if(!mobile.equals(accountInfo.getMobile())) {
			throw new AdminException(AdminErrCode.ERR_OTHER,"原手机号输入错误！");
		}
		return AdminResultVo.ok().setMsg("获取账户信息成功！");
	}
}
